﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using adc;

namespace tabtool {
    public enum TableFieldType {
        undefine_type,
        int_type,
        int64_type,
        float_type,
        double_type,
        string_type,
        list_type,
        map_type,
        tuple_type,
        enum_type,//枚举int
        mask_type,//掩码int
        date_type,//日期类型 格林位置时间int64
        struct_type
    }

    public class TableField {
        public string fieldName; //字段名
        public string fieldDesc; //描述注释
        public adc.base_type type;
        public List<string> conds = new List<string>();//条件数据

        public string Get(string s) {
            for (int i = 0; i < conds.Count(); i++) {
                if (conds[i] == s && i + 1 < conds.Count()) {
                    return conds[i + 1];
                }
            }
            return null;
        }

        internal string GetCppElemTypeName(base_type type)
        {
            switch (type.type) {
                case e_type.int_type:
                    return "int32_t";
                case e_type.int64_type:
                    return "int64_t";
                case e_type.float_type:
                    return "float";
                case e_type.double_type:
                    return "double";
                case e_type.string_type:
                    return "std::string";
                case e_type.list_type:
                    return string.Format("std::vector<{0}>", GetCppElemTypeName(((list_type)type).elem_type));
                case e_type.tuple_type: {
                    string ret = "std::tuple<";
                    foreach (var e in ((tuple_type)type).elem_types) {
                            ret += GetCppElemTypeName(e) + ",";
                    }
                    ret = ret.Substring(0, ret.Length - 1);
                    ret += ">";
                    return ret;
                }
                case e_type.struct_type:
                    return ((struct_type)type).struct_name; ;
            }
            throw new Exception("[AUTO_CODE_GET_ELEM_TYPE_ERROR] type: " + type.type);
        }
        public string GetCppTypeName()
        {
            switch (type.type) {
                case e_type.int_type:
                    return "int32_t";
                case e_type.int64_type:
                    return "int64_t";
                case e_type.float_type:
                    return "float";
                case e_type.double_type:
                    return "double";
                case e_type.string_type:
                    return "std::string";
                case e_type.enum_type: {
                    //return ((enum_type)type).table_name;
                    return "int32_t";
                }
                case e_type.mask_type:
                    return "int32_t";
                case e_type.date_type:
                    return "int64_t";
                case e_type.list_type:
                    return string.Format("std::vector<{0}>", GetCppElemTypeName(((list_type)type).elem_type));
                case e_type.map_type:
                    break;
                case e_type.tuple_type: { 
                    string ret = "std::tuple<";
                    foreach (var e in ((tuple_type)type).elem_types) {
                        ret += GetCppElemTypeName(e) + ",";
                    }
                    ret = ret.Substring(0, ret.Length - 1);
                    ret += ">";
                    return ret;
                }
                case e_type.struct_type:
                    return ((struct_type)type).struct_name;
            }
            throw new Exception("[AUTO_CODE_CPP_GET_TYPE_ERROR] type: " + type.type);
        }
        internal string GetCsharpElemTypeName(base_type type)
        {
            switch (type.type) {
                case e_type.int_type:
                    return "Int32";
                case e_type.int64_type:
                    return "Int64";
                case e_type.float_type:
                    return "float";
                case e_type.double_type:
                    return "double";
                case e_type.string_type:
                    return "string";
                case e_type.list_type:
                    return string.Format("List<{0}>", GetCsharpElemTypeName(((list_type)type).elem_type));
                case e_type.tuple_type: {
                        //CAN USE TUPLE VERSION > 4.0
                        if (Environment.Version.CompareTo(new Version("4.5")) > 0) {
                            string ret = "Tuple<";
                            foreach (var e in ((tuple_type)type).elem_types) {
                                ret += GetCsharpElemTypeName(e) + ",";
                            }
                            ret = ret.Substring(0, ret.Length - 1);
                            ret += ">";
                            return ret;
                        } else {
                            return "object[]";
                        }
                    }
                case e_type.struct_type: 
                    return ((struct_type)type).struct_name;
                    
            }
            throw new Exception("[AUTO_CODE_CSHARP_GET_ELEM_TYPE_ERROR] type: " + type.type);
        }
        public string GetCsharpTypeName()
        {
            switch (type.type) {
                case e_type.int_type:
                    return "Int32";
                case e_type.int64_type:
                    return "Int64";
                case e_type.float_type:
                    return "float";
                case e_type.double_type:
                    return "double";
                case e_type.string_type:
                    return "string";
                case e_type.enum_type: 
                    return "Int32";
                case e_type.mask_type:
                    return "Int32";
                case e_type.date_type:
                    return "Int64";
                case e_type.list_type:
                    return string.Format("List<{0}>", GetCsharpElemTypeName(((list_type)type).elem_type));
                case e_type.map_type:
                    break;
                case e_type.tuple_type: {
                        //CAN USE TUPLE VERSION > 4.0
                        if (Environment.Version.CompareTo(new Version("4.5")) > 0) {
                            string ret = "Tuple<";
                            foreach (var e in ((tuple_type)type).elem_types) {
                                ret += GetCsharpElemTypeName(e) + ",";
                            }
                            ret = ret.Substring(0, ret.Length - 1);
                            ret += ">";
                            return ret;
                        } else {
                            return "object[]";
                        }
                    }
                case e_type.struct_type:
                    return ((struct_type)type).struct_name;

            }
            throw new Exception("[AUTO_CODE_CSHARP_GET_TYPE_ERROR] type: " + type.type);
        }
        public string GetCsharpTemplateType()
        {
            switch (type.type) {
                case e_type.int_type:
                    return "N,N,N";
                case e_type.int64_type:
                    return "N,N,N";
                case e_type.float_type:
                    return "N,N,N";
                case e_type.double_type:
                    return "N,N,N";
                case e_type.string_type:
                    return "N,N,N";
                case e_type.enum_type:
                    return "N,N,N";
                case e_type.mask_type:
                    return "N,N,N";
                case e_type.date_type:
                    return "N,N,N";
                case e_type.list_type: {
                     list_type l = (list_type)type;
                     if(l.elem_type.type == e_type.list_type) {
                          list_type l2 = (list_type)l.elem_type;
                          return GetCsharpElemTypeName(l.elem_type) + "," + GetCsharpElemTypeName(l2.elem_type) + ",N";
                     } 
                     else if (l.elem_type.type == e_type.tuple_type) {
                            return "object[],N,N";
                     } 
                     else if(l.elem_type.type == e_type.struct_type){
                            return GetCsharpElemTypeName(l.elem_type) + ",N," + GetCsharpElemTypeName(l.elem_type);
                     } else {
                            return GetCsharpElemTypeName(l.elem_type) + ",N,N";
                     }
                }      
                case e_type.map_type:
                    break;
                case e_type.tuple_type:
                    return "N,N,N";
                case e_type.struct_type: {
                    struct_type s = (struct_type)type;
                    return "N,N," + s.struct_name;
                }
            }
            throw new Exception("[AUTO_CODE_CSHARP_TEMPLATE_TYPE_ERROR] type: " + type.type);
        }
        public string GetContainerType(string TableName) {
            if(type.type == adc.e_type.list_type) {
                return "list";
            }
            if(type.type == adc.e_type.map_type) {
                return "map";
            }
            throw new Exception("[GET_CONTAINER_TYPE_ERROR] Table:" + TableName + " Field:" + fieldName + " Illegal Container Type !!!");
        }


    }

    public class TableMeta {
        public List<TableField> Fields = new List<TableField>();
        public List<string> string_pool = new List<string>();//储存表中所有字符串(写入字符串时只写入索引 避免数据过大)
        public TableFieldType container_type = TableFieldType.undefine_type;
        public DataTable dt;//表数据
        public string TableName;//表名

        /// <summary>
        /// 构建c++  valid code
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public int BuildCppStr(StringBuilder builder, base_type type) {
            int len = 1;
            switch (type.type) {
                case e_type.int_type:
                case e_type.int64_type:
                case e_type.float_type:
                case e_type.double_type:
                case e_type.string_type:
                case e_type.enum_type:
                case e_type.mask_type:
                case e_type.date_type:
                    builder.AppendFormat("{0},", (int)type.type);
                    return 1;
                case e_type.tuple_type:
                    tuple_type t = (tuple_type)type;
                    builder.AppendFormat("{0},", (int)t.type);
                    foreach(var e in t.elem_types) {
                        len += BuildCppStr(builder, e);
                    }
                    return len;
                case e_type.list_type:
                    list_type l = (list_type)type;
                    builder.AppendFormat("{0},", (int)l.type);
                    len += BuildCppStr(builder, l.elem_type);
                    return len;
                case e_type.struct_type:
                    builder.AppendFormat("{0},", (int)type.type);
                    return 1;
            }
            throw new Exception("[AUTO_CODE_CPP_CHECK_ERROR] type: " + type.type);
        }

        /// <summary>
        /// 配置表名字 
        /// </summary>
        /// <returns></returns>
        public string GetTableName() {
            return TableName;
        }

        /// <summary>
        /// AUTOCODE 类名 
        /// </summary>
        /// <returns></returns>
        public string GetClassName(){
            return TableName.ToLower();
        }

        public string GetCppFileName()
        {
            return "adc_" + TableName.ToLower() + ".hpp";
        }

        public string GetCsharpFileName()
        {
            return "adc_" + TableName.ToLower() + ".cs";
        }


        /// <summary>
        /// 配置表容器类型
        /// </summary>
        /// <returns></returns>
        public string GetContainerType(){
            if(container_type == TableFieldType.list_type) {
                return "list";
            } else if(container_type == TableFieldType.map_type) {
                return "map";
            }
            throw new Exception("[GET_CONTAINER_TYPE_ERROR] Table:" + TableName +  " Illegal Container Type !!!");
        }

       
        /// <summary>
        /// 检查是否在string_pool中
        /// </summary>
        /// <param name="str"></param>
        /// <returns>是否存在</returns>
        public bool CheckStrPool(string str){
            foreach(string s in string_pool) {
                if (s == str) return true;
            }
            return false;
        }
        /// <summary>
        /// 获得在string_pool中的索引
        /// </summary>
        /// <param name="str"></param>
        /// <returns>索引</returns>
        public Int32 GetStrIndex(string str) {
            for(int i = 0; i < string_pool.Count; ++i) {
                if (string_pool[i] == str)
                    return i;
            }
            throw new Exception("[GET_STR_INDEX_ERROR] Str: " + str);
        }
    }
}
